#include "BasicTiming.h"
namespace smil
{
    BasicTiming::BasicTiming()
    {
        begin.is_set = dur.is_set = end.is_set = min.is_set = max.is_set = repeatCount.is_set = repeatDur.is_set = fill.is_set = false;
    };
    BasicTiming::~BasicTiming()
    {
    };
    duration BasicTiming::get_active_duration()
    {
        duration simple = get_simple_duration();
        duration p1; // length of count terations
        duration p2; // repeatDur
        duration iad; // the repeat length
        duration pad; // Repeat length trimmed for end
        duration active; // Length clipped to min/max
        duration indefinite = SYNC_INDEFINITE;
        duration mindur = 0;
        duration maxdur = SYNC_INDEFINITE;

        // BEGIN IAD CALCULATION
        if (repeatCount.is_set)
            p1 = simple * repeatCount.value; // When iterations can have different simple durations, this needs to add them, not multiply!
        else p1 = SYNC_INDEFINITE;
        if (repeatDur.is_set) p2 = repeatDur.value;
        else p2 = SYNC_INDEFINITE;

        if (simple == 0) iad = simple; // if the simple duration is zero then any multiple is zero
        else if (not (repeatCount.is_set or repeatDur.is_set)) iad = simple; // if they're not specified, set it to p0
        else iad = minimize(p1,p2).minimize(indefinite); // IAD = min(p1,p2,indefinite)
        // END IAD CALCULATION

        // BEGIN PAD CALCULATION
        if ((end.is_set) and not (dur.is_set or repeatCount.is_set or repeatDur.is_set))
            pad = end.value.resolve() - begin.value.resolve(); // equals all 3 W3 rules for this
        else if ((not end.is_set) or ((end.is_set) and (end.value.resolve() == indefinite)))
            pad = iad;
        else {
            duration length = end.value.resolve() - begin.value.resolve(); // minimize uses references // resolve is a temporary
            pad = minimize(iad,length); // I'm not clever enough to know a better way.
        }
        // END PAD CALCULATION

        if (min.is_set) mindur = min.value;
        if (max.is_set) maxdur = max.value;
        active = minimize(maxdur, maximize(mindur,pad));
        return active;
    };
    duration BasicTiming::get_implicit_duration()
    {
        duration implicit = SYNC_INDEFINITE;
        return implicit;
    };

    duration BasicTiming::get_simple_duration()
    {
        duration simple = get_implicit_duration(); // this will be rewritten by media elements
        if (end.is_set and not (dur.is_set or repeatCount.is_set or repeatDur.is_set))
        { //If end attribute but none of dur, repeatCount and repeatDur, simple duration is indefinite
            simple = SYNC_INDEFINITE;
            return simple;
        }
        if (dur.is_set and (dur.value.state != SYNC_UNRESOLVED))
        {
            simple = dur.value;
            return simple;
        }
        return simple; // ignoring dur = media for now
    };

}
